package com.xbongbong.paas.business.rule;

import com.xbongbong.i18n.util.I18nMessageUtil;
import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.domain.entity.BusinessRuleInfoEntity;
import com.xbongbong.paas.domain.entity.BusinessRuleLogEntity;
import com.xbongbong.paas.domain.entity.PaasFormEntity;
import com.xbongbong.paas.enums.BusinessRuleExecuteEnum;
import com.xbongbong.paas.enums.DelEnum;
import com.xbongbong.paas.enums.RuleOperationEnum;
import com.xbongbong.paas.help.ProFormHelp;
import com.xbongbong.paas.model.BusinessRuleInfoModel;
import com.xbongbong.paas.model.BusinessRuleLogModel;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.helper.PageHelper;
import com.xbongbong.paas.toolbox.util.DateTimeUtil;
import com.xbongbong.paas.toolbox.util.PageHelperUtil;
import com.xbongbong.paas.toolbox.util.StringUtil;
import com.xbongbong.pro.businessrulelog.pojo.BusinessRuleLogPojo;
import com.xbongbong.pro.businessrulelog.pojo.BusinessRuleLogSaveDTO;
import com.xbongbong.pro.businessrulelog.pojo.dto.BusinessRuleLogListDTO;
import com.xbongbong.pro.businessrulelog.pojo.vo.BusinessRuleLogListVO;
import com.xbongbong.pro.enums.businessrule.enums.BusinessRuleConsumerEnum;
import com.xbongbong.pro.enums.errorcodes.SystemErrorCodeEnum;
import com.xbongbong.pro.enums.permission.enums.ProPermissionAliasEnum;
import com.xbongbong.pro.form.pojo.RuleTargetPojo;
import com.xbongbong.pro.thread.ThreadPoolBeanConfig;
import com.xbongbong.saas.constant.StringConstant;
import com.xbongbong.saas.domain.entity.WorkOrderFormEntity;
import com.xbongbong.saas.enums.XbbRefTypeEnum;
import com.xbongbong.sys.domain.entity.UserEntity;
import com.xbongbong.sys.help.ProPermissionHelp;
import com.xbongbong.sys.model.UserModel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

/**
 * @author 吴峰
 * @version v1.0
 * @date 2020/5/9 16:29
 * @since v1.0
 */
@Service("businessRuleLogService")
public class BusinessRuleLogServiceImpl implements BusinessRuleLogService {

    private static final Logger LOGGER = LoggerFactory.getLogger(BusinessRuleLogServiceImpl.class);

    @Resource
    private BusinessRuleLogModel businessRuleLogModel;
    @Resource
    private ThreadPoolBeanConfig threadPoolBeanConfig;
    @Resource
    private ProFormHelp proFormHelp;
    @Resource
    private BusinessRuleInfoModel businessRuleInfoModel;
    @Resource
    private UserModel userModel;

    @Override
    public void log(BusinessRuleLogSaveDTO businessRuleLogSaveDTO, Integer executeResult, Integer executeNum, Integer consumer) throws XbbException {
       Long logId = businessRuleLogSaveDTO.getLogId();
        Runnable runnable = () -> {
            try {
                if (Objects.isNull(logId)) {
                    Long formId = businessRuleLogSaveDTO.getFormId();
                    RuleTargetPojo target = businessRuleLogSaveDTO.getTarget();
                    Long targetFormId = target.getFormId();
                    Long dataId = businessRuleLogSaveDTO.getDataId();
                    String corpid = businessRuleLogSaveDTO.getCorpid();
                    String userId = businessRuleLogSaveDTO.getUserId();
                    Integer businessType = businessRuleLogSaveDTO.getBusinessType();
                    Integer saasMark = businessRuleLogSaveDTO.getSaasMark();
                    Integer reason = businessRuleLogSaveDTO.getReason();
                    BusinessRuleLogEntity entity = new BusinessRuleLogEntity(corpid, saasMark, businessType, formId, dataId,
                            target.getLinkSaasMark(), target.getLinkBusinessType(), targetFormId,  reason,
                            businessRuleLogSaveDTO.getMessage(), consumer, businessRuleLogSaveDTO.getOperationType(), executeResult, executeNum, businessRuleLogSaveDTO.getBusinessRuleInfoId(),
                            businessRuleLogSaveDTO.getBusinessRuleType(), userId, businessRuleLogSaveDTO.getRedisKey());

                    businessRuleLogModel.insert(entity);
                }
            } catch (Exception e) {
                LOGGER.error("BusinessRuleLogServiceImpl.log 出错：", e);
            }

        };
        threadPoolBeanConfig.businessRuleLogThreadPool().execute(runnable);
    }

    @Override
    public void update(Long logId, String corpid, Integer consumer) throws XbbException {
        Runnable runnable = () -> {
            try {
                if (Objects.isNull(logId)) {
                } else {
                    BusinessRuleLogEntity entity = new BusinessRuleLogEntity(logId, corpid, consumer, DelEnum.NORMAL.getDel());

                    businessRuleLogModel.update(entity);
                }
            } catch (Exception e) {
                LOGGER.error("BusinessRuleLogServiceImpl.update 出错：", e);
            }
        };
        threadPoolBeanConfig.businessRuleLogThreadPool().execute(runnable);
    }


    @Override
    public BusinessRuleLogListVO list(BusinessRuleLogListDTO businessRuleLogListDTO) throws XbbException {
        BusinessRuleLogListVO businessRuleLogListVO = new BusinessRuleLogListVO();
        try {
            if (!ProPermissionHelp.hasThisPermission(businessRuleLogListDTO.getLoginUser(), ProPermissionAliasEnum.LOG_VIEW.getAlias())) {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100017);
            }
            String corpid = businessRuleLogListDTO.getCorpid();
            Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            param.put(StringConstant.CORPID, corpid);
            param.put(StringConstant.DEL, DelEnum.NORMAL.getDel());
            if (Objects.nonNull(businessRuleLogListDTO.getTriggerForm())) {
                param.put("businessType", businessRuleLogListDTO.getTriggerForm().getLinkBusinessType());
                param.put("formId", businessRuleLogListDTO.getTriggerForm().getFormId());
            }
            if (Objects.nonNull(businessRuleLogListDTO.getTargetForm())) {
                param.put("targetBusinessType", businessRuleLogListDTO.getTargetForm().getLinkBusinessType());
                param.put("targetFormId", businessRuleLogListDTO.getTargetForm().getFormId());
            }
            if (StringUtil.isNotEmpty(businessRuleLogListDTO.getExecuteUserId())) {
                param.put("creatorId", businessRuleLogListDTO.getExecuteUserId());
            }
            param.put("executeNum", businessRuleLogListDTO.getExecuteNum());
            param.put("performAction", businessRuleLogListDTO.getPerformAction());
            param.put("executeResult", businessRuleLogListDTO.getExecuteResult());
            param.put("consumer", businessRuleLogListDTO.getConsumer());
            param.put("reasonMessage", businessRuleLogListDTO.getReasonMessage());
            param.put("startTime", businessRuleLogListDTO.getOperateMinTime());
            param.put("endTime", businessRuleLogListDTO.getOperateMaxTime());
            param.put("orderByStr", "update_time desc");
            PageHelper pageHelper = PageHelperUtil.getPageHelper(param, businessRuleLogModel, businessRuleLogListDTO.getPage(), businessRuleLogListDTO.getPageSize());
            List<BusinessRuleLogEntity> list = (List<BusinessRuleLogEntity>) PageHelperUtil.getEntityList(param, pageHelper, businessRuleLogModel);
            Set<Long> formIdList = new HashSet<>();
            Set<Long> workOrderFormIdList = new HashSet<>();
            Set<Long> businessRuleIdList = new HashSet<>();
            Set<String> userIdSet = new HashSet<>();

            list.forEach(item->{
                businessRuleIdList.add(item.getBusinessRuleInfoId());
                Long formId = item.getFormId();
                userIdSet.add(item.getCreatorId());
                if (Objects.equals(XbbRefTypeEnum.WORK_ORDER.getCode(), item.getBusinessType())) {
                    workOrderFormIdList.add(formId);
                } else {
                    formIdList.add(formId);
                }
                Long targetFormId = item.getTargetFormId();
                if (Objects.equals(XbbRefTypeEnum.WORK_ORDER.getCode(), item.getTargetBusinessType())) {
                    workOrderFormIdList.add(targetFormId);
                } else {
                    formIdList.add(targetFormId);
                }
            });
            param.clear();
            param.put(StringConstant.CORPID, corpid);
            param.put(StringConstant.DEL, DelEnum.NORMAL.getDel());
            param.put(StringConstant.IDIN, businessRuleIdList);
            List<BusinessRuleInfoEntity> businessRuleInfoList = businessRuleInfoModel.findEntitys(param);
            Map<String, String> businessRuleMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            businessRuleInfoList.forEach(item->{
                if (StringUtil.isNotEmpty(item.getActiveName())) {
                    businessRuleMap.put(item.getId()+"_1", item.getActiveName());
                }
                if (StringUtil.isNotEmpty(item.getInactiveName())) {
                    businessRuleMap.put(item.getId()+"_2", item.getInactiveName());
                }
            });
            // 目标表单
            Map<Long, PaasFormEntity> targetExplain = proFormHelp.getFormMap(formIdList, corpid, null);
            Map<Long, WorkOrderFormEntity> workOrderExplain = proFormHelp.getWorkOrderFormMap(workOrderFormIdList, corpid, null);
            Map<Integer, RuleOperationEnum> operationMap = RuleOperationEnum.getOperationMap();
            List<String> userIdList = new ArrayList<>(userIdSet);
            List<UserEntity> userList = userModel.findEntitysByUserIds(userIdList, corpid);
            Map<String, String> userMap = new HashMap<>(userList.size());
            userList.forEach(item->{
                userMap.put(item.getUserId(), item.getName());
            });
            List<BusinessRuleLogPojo> businessRuleLogList = new ArrayList<>();
            list.forEach(item->{
                String formName = null;
                Long formId = item.getFormId();
                if (Objects.equals(XbbRefTypeEnum.WORK_ORDER.getCode(), item.getBusinessType()) && workOrderExplain.containsKey(formId)) {
                    formName = workOrderExplain.get(formId).getName();
                } else if (targetExplain.containsKey(formId)) {
                    formName = targetExplain.get(formId).getName();
                }
                Long targetFormId = item.getTargetFormId();
                String targetFormName = null;
                if (Objects.equals(XbbRefTypeEnum.WORK_ORDER.getCode(), item.getTargetBusinessType()) && workOrderExplain.containsKey(targetFormId)) {
                    targetFormName = workOrderExplain.get(targetFormId).getName();
                } else if (targetExplain.containsKey(targetFormId)) {
                    targetFormName = targetExplain.get(targetFormId).getName();
                }
                String performAction = I18nMessageUtil.getMessage(operationMap.get(item.getPerformAction()).getMemo());
                RuleOperationEnum ruleOperationEnum = operationMap.get(item.getExecuteResult());
                String executeResult = I18nMessageUtil.getMessage(ruleOperationEnum.getTip());
                Integer businessRuleType = item.getBusinessRuleType();
                String name = businessRuleMap.get(item.getBusinessRuleInfoId()+"_"+businessRuleType);
                String message = item.getReasonMessage();
                String consumer = I18nMessageUtil.getMessage(BusinessRuleConsumerEnum.SUCCESS.getMemo());
                Integer consumerFlag = item.getConsumer();
                if(Objects.equals(1, consumerFlag)) {
                    if (Objects.equals(item.getPerformAction(), RuleOperationEnum.UPDATE_AND_INSERT.getType())) {
                        // 更新和插入数据；
                        if (Objects.equals(RuleOperationEnum.ONLY_INSERT.getType(), item.getExecuteResult())) {
                            message = String.format(I18nMessageUtil.getMessage(operationMap.get(RuleOperationEnum.ONLY_UPDATE.getType()).getTip()), 0)
                                    +"、" + String.format(I18nMessageUtil.getMessage(operationMap.get(RuleOperationEnum.ONLY_INSERT.getType()).getTip()), item.getExecuteNum());
                        }else if (Objects.equals(RuleOperationEnum.ONLY_UPDATE.getType(), item.getExecuteResult())) {
                            if (item.getExecuteNum() > PaasConstant.LIMIT_MAX_NUM) {
                                consumerFlag = 0;
                                message = item.getReasonMessage();
                            } else {
                                message = String.format(I18nMessageUtil.getMessage(operationMap.get(RuleOperationEnum.ONLY_UPDATE.getType()).getTip()), item.getExecuteNum())
                                        +"、" + String.format(I18nMessageUtil.getMessage(operationMap.get(RuleOperationEnum.ONLY_INSERT.getType()).getTip()), 0);
                            }
                        }
                    } else if (Objects.equals(RuleOperationEnum.ONLY_UPDATE.getType(), item.getExecuteResult())) {
                        if (item.getExecuteNum() > PaasConstant.LIMIT_MAX_NUM) {
                            consumerFlag = 0;
                            message = item.getReasonMessage();
                        } else if (item.getExecuteNum() == 0) {
                            if (Objects.equals(BusinessRuleExecuteEnum.PRECONDITION_CHECK_FAILED.getCode(), item.getReason())) {
                                message = item.getReasonMessage();
                            } else {
                                // 无更新数据或者无删除数据
                                message = String.format(executeResult, item.getExecuteNum()) + "，" + BusinessRuleExecuteEnum.NO_DATA.getMessage();
                            }
                        } else {
                            message = String.format(executeResult, item.getExecuteNum());
                        }
                    } else if (Objects.equals(RuleOperationEnum.ONLY_DELETE.getType(), item.getExecuteResult()) && item.getExecuteNum() == 0) {
                        // 无更新数据或者无删除数据
                        message = String.format(executeResult, item.getExecuteNum()) + "，" + BusinessRuleExecuteEnum.NO_DATA.getMessage();
                    }else if (Objects.equals(BusinessRuleExecuteEnum.PRECONDITION_CHECK_FAILED.getCode(), item.getReason())) {
                        message = item.getReasonMessage();
                    } else {
                        message = String.format(executeResult, item.getExecuteNum());
                    }
                } else {
                    consumer = I18nMessageUtil.getMessage(BusinessRuleConsumerEnum.FAILED.getMemo());
                    message = consumer + "：" + message;
                }
                String userName = userMap.get(item.getCreatorId());
                BusinessRuleLogPojo businessRuleLogPojo = new BusinessRuleLogPojo(item.getId(), formName, targetFormName, message, consumer, consumerFlag,
                        performAction, executeResult, item.getExecuteNum(), name, DateTimeUtil.getString(item.getUpdateTime()*1000), userName);
                businessRuleLogList.add(businessRuleLogPojo);
            });
            businessRuleLogListVO.setBusinessRuleLogList(businessRuleLogList);
            businessRuleLogListVO.setPageHelper(pageHelper);
        } catch (XbbException e) {
            throw e;
        } catch (Exception e) {
            LOGGER.error("BusinessRuleLogServiceImpl.list 出错：", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001);
        }
        return businessRuleLogListVO;
    }
}
